#include "BaseEncoder.h"

static const rfbPixelFormat BGR233Format = {
    8, 8, 0, 1, 7, 7, 3, 0, 3, 6
};

BaseEncoder::BaseEncoder()
{
	m_transtable = 0;
	m_transfunc = 0;
	m_SWOffsetx = 0;
	m_SWOffsety = 0;
}

BaseEncoder::~BaseEncoder()
{
	if( m_transtable )
	{
		free(m_transtable);
		m_transtable = 0;
	}
}

bool BaseEncoder::SetPixelFormat(const rfbPixelFormat& tLocalFormat,const rfbPixelFormat& tRemoteFormat )
{
	m_tLocalFormat = tLocalFormat;
	m_tRemoteFormat = tRemoteFormat;

	return SetTranslateFunction();
}

bool BaseEncoder::SetTranslateFunction()
{
	m_transformat = m_tRemoteFormat;
	if ((m_transformat.bitsPerPixel != 8) &&
		(m_transformat.bitsPerPixel != 16) &&
		(m_transformat.bitsPerPixel != 32))
    {
		return false;
    }
	
    if ((m_localformat.bitsPerPixel != 8) &&
		(m_localformat.bitsPerPixel != 16) &&
		(m_localformat.bitsPerPixel != 32))
    {
		
		return false;
    }
	
	if (!m_transformat.trueColour && (m_transformat.bitsPerPixel != 8))
	{
		return false;
	}
	if (!m_localformat.trueColour && (m_localformat.bitsPerPixel != 8))
	{
		return false;
	}
	
	// Now choose the translation function to use
	
	// We don't do remote palettes unless they're 8-bit
    if (!m_transformat.trueColour)
	{
		// Is the local format the same?
		if (!m_localformat.trueColour &&
			(m_localformat.bitsPerPixel == m_transformat.bitsPerPixel))
		{
			// Yes, so don't do any encoding
			m_transfunc = rfbTranslateNone;
			
			// The first time the client sends an update, it will call
			// GetRemotePalette to get the palette information required
			return true;
		}
		else if (m_localformat.trueColour)
		{
			// Local side is truecolour, remote is palettized
			// Fill out the translation table as if writing to BGR233
			m_transformat = BGR233Format;
			
			// Continue on down to the main translation section
		}
		else
		{
			// No, so not supported yet...
			return false;
		}
	}
	
	// REMOTE FORMAT IS true-COLOUR
	
	// Handle 8-bit palette-based local data
	if (!m_localformat.trueColour)
	{
		// 8-bit palette to truecolour...
		
		// Yes, so pick the right translation function!
		m_transfunc = rfbTranslateWithSingleTableFns
			[m_localformat.bitsPerPixel / 16]
			[m_transformat.bitsPerPixel / 16];
		
		(*rfbInitColourMapSingleTableFns[m_transformat.bitsPerPixel / 16])
			(&m_transtable, &m_localformat, &m_transformat);
		return m_transtable != 0;
	}
	
	// If we reach here then we're doing truecolour to truecolour
	
	// Are the formats identical?
    if (PF_EQ(m_transformat,m_localformat))
	{
		// Yes, so use the null translation function
		m_transfunc = rfbTranslateNone;
		
		return true;
    }
	
	// Is the local display a 16-bit one
    if (m_localformat.bitsPerPixel == 16)
	{
		// Yes, so use a single lookup-table
		m_transfunc = rfbTranslateWithSingleTableFns
			[m_localformat.bitsPerPixel / 16]
			[m_transformat.bitsPerPixel / 16];
		
		(*rfbInittrueColourSingleTableFns[m_transformat.bitsPerPixel / 16])
			(&m_transtable, &m_localformat, &m_transformat);
    }
	else
	{
		// No, so use three tables - one for each of R, G, B.
		m_transfunc = rfbTranslateWithRGBTablesFns
			[m_localformat.bitsPerPixel / 16]
			[m_transformat.bitsPerPixel / 16];
		
		(*rfbInittrueColourRGBTablesFns[m_transformat.bitsPerPixel / 16])
			(&m_transtable, &m_localformat, &m_transformat);
    }
	
	return (m_transtable != 0);
}

void BaseEncoder::SetSWOffset( int x,int y)
{
	m_SWOffsetx = x;
	m_SWOffsety = y;
}

unsigned int BaseEncoder::EncodeRect(BYTE* pszSrcBuf,BYTE* pszDestBuf,const rfb::Rect& rect)
{
	// Create the header for the update in the destination area
	rfbFramebufferUpdateRectHeader *surh = (rfbFramebufferUpdateRectHeader *)pszDestBuf;
	surh->r.x = (CARD16) (rect.tl.x-m_SWOffsetx);
	surh->r.y = (CARD16) (rect.tl.y-m_SWOffsety);
	surh->r.w = (CARD16) (rect.br.x-rect.tl.x);
	surh->r.h = (CARD16) (rect.br.y-rect.tl.y);
	surh->r.x = Swap16IfLE(surh->r.x);
	surh->r.y = Swap16IfLE(surh->r.y);
	surh->r.w = Swap16IfLE(surh->r.w);
	surh->r.h = Swap16IfLE(surh->r.h);
	surh->encoding = Swap32IfLE(rfbEncodingRaw);

	// Translate the data in place in the output buffer
	Translate(pszSrcBuf, pszDestBuf + sz_rfbFramebufferUpdateRectHeader, rect);

	// Return the buffer size
	return sz_rfbFramebufferUpdateRectHeader +
		((rect.br.x-rect.tl.x)*(rect.br.y-rect.tl.y)*m_remoteformat.bitsPerPixel) / 8;
}